//
// Created by Administrator on 2021/4/23.
//


/*给你一个由 无重复 正整数组成的集合 nums ，请你找出并返回其中最大的整除子集 answer ，子集中每一元素对 (answer[i], answer[j]) 都应当满足：
answer[i] % answer[j] == 0 ，或
        answer[j] % answer[i] == 0
如果存在多个有效解子集，返回其中任何一个均可。


示例 1：
输入：nums = [1,2,3]
输出：[1,2]
解释：[1,3] 也会被视为正确答案。

示例 2：
输入：nums = [1,2,4,8]
输出：[1,2,4,8]

提示：
1 <= nums.length <= 1000
1 <= nums[i] <= 2 * 109
nums 中的所有整数 互不相同

        来源：力扣（LeetCode）
链接：https://leetcode-cn.com/problems/largest-divisible-subset
著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。*/

#include <vector>
#include <iostream>
#include <algorithm>

using namespace std;

class Solution {
public:
    /**
    f[i]:以nums[i]为结尾的最大整除子集
            f[i] = max(f[j])+1, 0 < j <= i ,nums[i]%nums[j] == 0
    f[1] = 1
    **/
    vector<int> largestDivisibleSubset(vector<int> &nums) {
        sort(nums.begin(), nums.end()); // 先给个排序
        auto n = nums.size();
        vector<int> f(n, 1); // 记录最大长度
        vector<vector<int>> g(n);
        int i,j;
        for (i = 0; i < n; ++i) {
            int formerIndex = i;
            for ( j = 0; j < i; ++j) { // 找到i前面能够被i整除的最大数，将nums[i]添加到后面
                if (nums[i] % nums[j] == 0) {
                    if (f[j] + 1 > f[i]) {
                        f[i] = f[j] + 1;
                        formerIndex = j;
                    }
                }
            }
            // 这么做好像会得到一个非常大的g 如果数据比较大
            g[i] = g[formerIndex];
            g[i].push_back(nums[i]);
        }
        auto target = max_element(f.begin(), f.end());
        for ( i = 0; i < n; ++i) {
            if (f[i] == *target) {
                break;
            }
        }
        return g[i];
    }
};
class Solution2 {  // 题解
public:
    vector<int> largestDivisibleSubset(vector<int>& nums) {
        auto len = nums.size();
        sort(nums.begin(), nums.end());

        // 第 1 步：动态规划找出最大子集的个数、最大子集中的最大整数
        vector<int> dp(len, 1);
        int maxSize = 1;
        int maxVal = dp[0];
        for (int i = 1; i < len; i++) {
            for (int j = 0; j < i; j++) {
                // 题目中说「没有重复元素」很重要
                if (nums[i] % nums[j] == 0) {
                    dp[i] = max(dp[i], dp[j] + 1);
                }
            }
            // 记录最大长度和最大值
            if (dp[i] > maxSize) {
                maxSize = dp[i];
                maxVal = nums[i];
            }
        }

        // 第 2 步：倒推获得最大子集
        vector<int> res;
        if (maxSize == 1) {
            res.push_back(nums[0]);
            return res;
        }

        for (auto i = len - 1; i >= 0 && maxSize > 0; i--) {
            if (dp[i] == maxSize && maxVal % nums[i] == 0) {
                res.push_back(nums[i]);
                maxVal = nums[i];
                maxSize--;
            }
        }
        return res;
    }
};

int main() {
    Solution2 sol;
    vector<int> v1{1, 2, 4,8};
    vector<int> ans = sol.largestDivisibleSubset(v1);
    for (auto &x:ans) cout << x << endl;
    return 0;
}